#ifndef __LOGGER_H__
#define __LOGGER_H__

#include "util.hpp"
#include "logLevel.hpp"
#include "lopper.hpp"
#include "sink.hpp"
#include "buffer.hpp"
#include "format.hpp"
#include <atomic>
#include <unordered_map>
#include <mutex>
#include <cstdarg>

namespace sqy_log
{

    struct Logger
    {
        public:
            using ptr = std::shared_ptr<Logger>;
            Logger(const std::string& logger_name,
                LogLevel::value level,
                Formatter::ptr& Formatter,
                std::vector<LogSink::ptr>& sinks)
                :_logger_name(logger_name),
                _limit_level(level),
                _formatter(Formatter),
                _sinks(sinks.begin(),sinks.end())
            {}

            const std::string& name()
            {
                return _logger_name;
            }
            //完成构造日志消息对象过程并进行格式化，得到格式化后额日志消息字符串--然后进行落地输出
            void debug(const std::string&file,size_t line, const std::string& fmt, ...)
            {
                //通过传入的参数构造除一个日志消息对象，进行日志的格式化，最终落地
                //1.判断当前的日志是否达到输出等级
                if(LogLevel::value::DEBUG < _limit_level){return;}
                //2.对fmt进行格式化字符串和不定参进行字符串组织，得到的日志消息的字符串
                char* res;
                va_list ap;
                va_start(ap,fmt);//初始化ap指针，使其指向count后面的第一个参数
                int len = vasprintf(&res,fmt.c_str(),ap);
                if(len == -1)
                {
                    std::cout << "vasprintf failed!!\n";
                    return;
                }
                va_end(ap);//将ap置空
                serialize(LogLevel::value::DEBUG,file,line,res);
                free(res);//注意释放
            }
            void info(const std::string&file,size_t line, const std::string& fmt, ...)
            {
                if(LogLevel::value::INFO < _limit_level){return;}
                char* res;
                va_list ap;
                va_start(ap,fmt);
                int len = vasprintf(&res,fmt.c_str(),ap);
                if(len == -1)
                {
                    std::cout << "vasprintf failed!!\n";
                    return;
                }
                va_end(ap);
                serialize(LogLevel::value::INFO,file,line,res);
                free(res);
            }
            void warn(const std::string&file,size_t line, const std::string& fmt, ...)
            {
                if(LogLevel::value::WARING < _limit_level){return;}
                char* res;
                va_list ap;
                va_start(ap,fmt);//初始化ap指针，使其指向count后面的第一个参数
                int len = vasprintf(&res,fmt.c_str(),ap);
                if(len == -1)
                {
                    std::cout << "vasprintf failed!!\n";
                    return;
                }
                va_end(ap);//将ap置空
                serialize(LogLevel::value::WARING,file,line,res);
                free(res);//注意释放
            }
            void error(const std::string&file,size_t line, const std::string& fmt, ...)
            {
                if(LogLevel::value::ERROR < _limit_level){return;}
                char* res;
                va_list ap;
                va_start(ap,fmt);
                int len = vasprintf(&res,fmt.c_str(),ap);
                if(len == -1)
                {
                    std::cout << "vasprintf failed!!\n";
                    return;
                }
                va_end(ap);//将ap置空
                serialize(LogLevel::value::ERROR,file,line,res);
                free(res);//注意释放
            }
            void fatal(const std::string&file,size_t line, const std::string& fmt, ...)
            {
                if(LogLevel::value::FATAL< _limit_level){return;}
                char* res;
                va_list ap;
                va_start(ap,fmt);
                int len = vasprintf(&res,fmt.c_str(),ap);
                if(len == -1)
                {
                    std::cout << "vasprintf failed!!\n";
                    return;
                }
                va_end(ap);//将ap置空
                serialize(LogLevel::value::FATAL,file,line,res);
                free(res);//注意释放
            }
        protected:
            void serialize(LogLevel::value level,const std::string&file,size_t line,const char * res)
            {
                //3.构造LogMsg对象
                LogMsg msg(level,line,file,_logger_name,res);
                //4.通过格式化工具对LogMsg进行格式化，得到格式化的日志字符串
                std::stringstream ss;
                _formatter->format(ss,msg);
                //5.进行日志落地
                log(ss.str().c_str(),ss.str().size());
            }
            //对log进行抽象
            virtual void log(const char* data,size_t len) = 0;
        protected:
            std::mutex _mutex;//加锁，线程安全进行
            std::string _logger_name;//日志器名称
            std::atomic<LogLevel::value> _limit_level;//限制等级
            Formatter::ptr _formatter;
            std::vector<LogSink::ptr> _sinks;
    };

    class SyncLogger : public Logger //同步日志器
    {
        public:
            SyncLogger(const std::string& logger_name,
                LogLevel::value level,
                Formatter::ptr& Formatter,
                std::vector<LogSink::ptr>& sinks)
                :Logger(logger_name,level,Formatter,sinks)
                {}
        protected:
        //同步日志器，是将日志直接通过落地模块句柄进行日志落地
        void log(const char* data,size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_sinks.empty()) return;//为空直接返回
            for(auto& sink : _sinks)
            {
                sink->log(data,len);
            }
        }
    };

    class AsyncLogger : public Logger
    {
        public:
            AsyncLogger(const std::string& logger_name,
                    LogLevel::value level,
                    Formatter::ptr& formatter,
                    std::vector<LogSink::ptr>& sinks,
                    AsyncType lopper_type):
                    Logger(logger_name, level, formatter,sinks),
                    //因为类中有this指针，所以需要用bind来进行绑定
                    _lopper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), lopper_type))
                    {}
                    

            void log(const char* data, size_t len)//将数据写入缓冲区
            {
                _lopper->push(data,len);
            }

            //设计一个实际落地函数（将缓冲区数据实际落地）
            void realLog(Buffer& buf)//所要传入的回调函数，进行日志落地
            {
                if(_sinks.empty()) return;
                for(auto& sink : _sinks)
                {
                    sink->log(buf.begin(),buf.readAbleSize());
                }
            }

        private:
            AsyncLooper::ptr _lopper;
    };

     //使用建造者模式来建造日志器，而不要让用户直接去构造日志器，简化用户的使用复杂度
    //抽象一个日志器建造者类（完成日志器对象所需零部件的构建&日志器的构建）
    //1.设置日志器类型
    //2.将不同类型的日志器的创建放到同一个日志器建造者类中完成
    enum LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };

    class LoggerBuilder
    {
        public:
        LoggerBuilder():
            _logger_type(LoggerType::LOGGER_SYNC),
            _limit_level(LogLevel::value::DEBUG),
            _loop_type(AsyncType::ASYNC_SAFE)
            {}
        void buildEnableUnsafeAsync()
        {
            _loop_type = AsyncType::ASYNC_UNSAFE;
        }
        void buildLoggerType(LoggerType type)
        {
            _logger_type = type;
        }
        void buildLoggerName(const std::string& name)
        {
            _logger_name = name;
        }
        void buildLoggerLevel(LogLevel::value level)
        {   
            _limit_level = level;
        }
        void buildFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template<typename SinkType, typename ...Args>
        void buildSink(Args &&...args)
        {
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual Logger::ptr build() = 0;
        protected:
        AsyncType _loop_type;
        LoggerType _logger_type;
        std::string _logger_name;
        LogLevel::value _limit_level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };
    //2.派生出具体的建造者类---局部日志器的建造者 & 全局的日志器建造者（后边添加了全局单例管理器之后，将日志器添加全局管理）
    class LocalLoggerBuilder : public LoggerBuilder
    {
        public:
            Logger::ptr build() override
            {
                assert(!_logger_name.empty());//必须要有日志器名称
                if(_formatter.get() == nullptr)
                {
                    _formatter = std::make_shared<Formatter>();
                }
                if(_sinks.empty())
                {
                    buildSink<StdoutSink>();
                }
                if( _logger_type == LoggerType::LOGGER_ASYNC)
                {
                    return std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_loop_type);
                }
                return std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
            }
    };


    class LoggerMangger
    {
        public:
            static LoggerMangger& getInstance()
            {
                //在c++11后，针对静态局部变量，编译器在编译的层面实现了线程安全
                //当静态局部变量没有构造完成之前，其他线程进入就会阻塞
                static LoggerMangger eton;
                return eton;
            }

            void addLogger(Logger::ptr& logger)//添加日志器管理
            {
                if(hasLogger(logger->name()))
                {
                    return;//该日志器名称已经存在，不需要添加
                }
                std::unique_lock<std::mutex> lock(_mutex);
                _loggers.insert(std::make_pair(logger->name(),logger));
            }
            
            bool hasLogger(const std::string& name)//判断是否管理了指定名称的日志器
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _loggers.find(name);
                if(it == _loggers.end())
                {
                    return false;
                }
                return true;
            }

            Logger::ptr getLogger(const std::string& name)//获取日志器
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _loggers.find(name);
                if(it == _loggers.end())
                {
                    return Logger::ptr();
                }
                return it->second;
            }

            Logger::ptr rootLogger()
            {
                return _root_logger;
            }

        private:
            LoggerMangger()
            {
                //注意这里不能用全局的日志器建造者，否则会导致死循环26*
                std::unique_ptr<sqy_log::LoggerBuilder> builder(new sqy_log::LocalLoggerBuilder());
                builder->buildLoggerName("root");
                _root_logger = builder->build();
                _loggers.insert(std::make_pair("root",_root_logger));
            }
        private:
            std::mutex _mutex;//互斥锁
            Logger::ptr _root_logger;//默认日志器
            std::unordered_map<std::string,Logger::ptr> _loggers;
    };

    class GlobalLoggerBuilder : public LoggerBuilder
    {
        public:
            Logger::ptr build() override
            {
                assert(!_logger_name.empty());//必须要有日志器名称
                if(_formatter.get() == nullptr)
                {
                    _formatter = std::make_shared<Formatter>();
                }
                if(_sinks.empty())
                {
                    buildSink<StdoutSink>();
                }
                Logger::ptr logger;
                if( _logger_type == LoggerType::LOGGER_ASYNC)
                {
                    logger = std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_loop_type);
                }
                else
                {
                    logger = std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
                }
                LoggerMangger::getInstance().addLogger(logger);
                return logger;
            }
    };
}

#endif
